﻿using System;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;

namespace Brain.Windows
{
    public class GraphicsDeviceService : IGraphicsDeviceService
    {
        private GraphicsDevice device;

        /// <summary>
        /// The Only Single Active instance of GraphicsDeviceService
        /// </summary>
        public static GraphicsDeviceService SingleInstance;

        private static int referenceCount;

        /// <summary>
        /// Presentation Parameters, includes Back Buffer size 
        /// </summary>
        public static PresentationParameters PresentationParameters;

        /// <summary>
        /// Event for handling when the Device is created
        /// </summary>
        public event EventHandler<EventArgs> DeviceCreated;

        /// <summary>
        /// Event for handling when the Device is Disposing
        /// </summary>
        public event EventHandler<EventArgs> DeviceDisposing;

        /// <summary>
        /// Event for handling when the Device is resetted
        /// </summary>
        public event EventHandler<EventArgs> DeviceReset;

        /// <summary>
        /// Event for handling when the Device is resetting
        /// </summary>
        public event EventHandler<EventArgs> DeviceResetting;

        /// <summary>
        /// The Graphics Device
        /// </summary>
        public GraphicsDevice GraphicsDevice
        {
            get { return device; }
        }

        /// <summary>
        /// This class is a singleton: there is only one instance. Thus, the constructor is private
        /// </summary>
        /// <param name="windowHandle"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        private GraphicsDeviceService(IntPtr windowHandle, int width, int height)
        {
            PresentationParameters = new PresentationParameters();

            PresentationParameters.BackBufferWidth = Math.Max(width, 1);
            PresentationParameters.BackBufferHeight = Math.Max(height, 1);
            PresentationParameters.BackBufferFormat = SurfaceFormat.Color;

            PresentationParameters.DeviceWindowHandle = windowHandle;

            PresentationParameters.DepthStencilFormat = DepthFormat.Depth16;
            PresentationParameters.IsFullScreen = false;

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, GraphicsProfile.HiDef,
                PresentationParameters);
        }

        /// <summary>
        /// Creates a Reference to the GraphicsDevcie Service class
        /// </summary>
        /// <param name="windowHandle"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static GraphicsDeviceService AddRef(IntPtr windowHandle, int width, int height)
        {
            // Increment the "how many controls sharing the device" reference count.
            if (Interlocked.Increment(ref referenceCount) == 1)
            {
                // If this is the first control to start using the
                // device, we must create the singleton instance.
                SingleInstance = new GraphicsDeviceService(windowHandle,
                                                              width, height);
            }

            return SingleInstance;
        }

        /// Releases a reference to the singleton instance.
        public void Release(bool disposing)
        {
            // Decrement the "how many controls sharing the device" reference count.
            if (Interlocked.Decrement(ref referenceCount) == 0)
            {
                // If this is the last control to finish using the
                // device, we should dispose the singleton instance.
                if (disposing)
                {
                    if (DeviceDisposing != null)
                        DeviceDisposing(this, EventArgs.Empty);

                    device.Dispose();
                }

                device = null;
            }
        }

        // Causes the device to fill its contents
        public void ResetDevice(int width, int height)
        {
            if (DeviceResetting != null)
                DeviceResetting(this, EventArgs.Empty);

            PresentationParameters.BackBufferWidth = Math.Max(PresentationParameters.BackBufferWidth, width);
            PresentationParameters.BackBufferHeight = Math.Max(PresentationParameters.BackBufferHeight, height);

            device.Reset(PresentationParameters);

            if (DeviceReset != null)
                DeviceReset(this, EventArgs.Empty);
        }
    }
}
